home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2000 March / maximum-cd-2000-03.iso / Quake3 Game Source / Q3AGameSource.exe / Main / bg_pmove.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-18  |  41.0 KB  |  1,879 lines

  1. // Copyright (C) 1999-2000 Id Software, Inc.
  2. //
  3. // bg_pmove.c -- both games player movement code
  4. // takes a playerstate and a usercmd as input and returns a modifed playerstate
  5.  
  6. #include "q_shared.h"
  7. #include "bg_public.h"
  8. #include "bg_local.h"
  9.  
  10. pmove_t        *pm;
  11. pml_t        pml;
  12.  
  13. // movement parameters
  14. float    pm_stopspeed = 100;
  15. float    pm_duckScale = 0.25;
  16. float    pm_swimScale = 0.50;
  17. float    pm_wadeScale = 0.70;
  18.  
  19. float    pm_accelerate = 10;
  20. float    pm_airaccelerate = 1;
  21. float    pm_wateraccelerate = 4;
  22. float    pm_flyaccelerate = 8;
  23.  
  24. float    pm_friction = 6;
  25. float    pm_waterfriction = 1;
  26. float    pm_flightfriction = 3;
  27.  
  28. int        c_pmove = 0;
  29.  
  30.  
  31. /*
  32. ===============
  33. PM_AddEvent
  34.  
  35. ===============
  36. */
  37. void PM_AddEvent( int newEvent ) {
  38.     BG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps );
  39. }
  40.  
  41. /*
  42. ===============
  43. PM_AddTouchEnt
  44. ===============
  45. */
  46. void PM_AddTouchEnt( int entityNum ) {
  47.     int        i;
  48.  
  49.     if ( entityNum == ENTITYNUM_WORLD ) {
  50.         return;
  51.     }
  52.     if ( pm->numtouch == MAXTOUCH ) {
  53.         return;
  54.     }
  55.  
  56.     // see if it is already added
  57.     for ( i = 0 ; i < pm->numtouch ; i++ ) {
  58.         if ( pm->touchents[ i ] == entityNum ) {
  59.             return;
  60.         }
  61.     }
  62.  
  63.     // add it
  64.     pm->touchents[pm->numtouch] = entityNum;
  65.     pm->numtouch++;
  66. }
  67.  
  68. /*
  69. ===================
  70. PM_StartTorsoAnim
  71. ===================
  72. */
  73. static void PM_StartTorsoAnim( int anim ) {
  74.     if ( pm->ps->pm_type >= PM_DEAD ) {
  75.         return;
  76.     }
  77.     pm->ps->torsoAnim = ( ( pm->ps->torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
  78.         | anim;
  79. }
  80. static void PM_StartLegsAnim( int anim ) {
  81.     if ( pm->ps->pm_type >= PM_DEAD ) {
  82.         return;
  83.     }
  84.     if ( pm->ps->legsTimer > 0 ) {
  85.         return;        // a high priority animation is running
  86.     }
  87.     pm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
  88.         | anim;
  89. }
  90.  
  91. static void PM_ContinueLegsAnim( int anim ) {
  92.     if ( ( pm->ps->legsAnim & ~ANIM_TOGGLEBIT ) == anim ) {
  93.         return;
  94.     }
  95.     if ( pm->ps->legsTimer > 0 ) {
  96.         return;        // a high priority animation is running
  97.     }
  98.     PM_StartLegsAnim( anim );
  99. }
  100.  
  101. static void PM_ContinueTorsoAnim( int anim ) {
  102.     if ( ( pm->ps->torsoAnim & ~ANIM_TOGGLEBIT ) == anim ) {
  103.         return;
  104.     }
  105.     if ( pm->ps->torsoTimer > 0 ) {
  106.         return;        // a high priority animation is running
  107.     }
  108.     PM_StartTorsoAnim( anim );
  109. }
  110.  
  111. static void PM_ForceLegsAnim( int anim ) {
  112.     pm->ps->legsTimer = 0;
  113.     PM_StartLegsAnim( anim );
  114. }
  115.  
  116.  
  117. /*
  118. ==================
  119. PM_ClipVelocity
  120.  
  121. Slide off of the impacting surface
  122. ==================
  123. */
  124. void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ) {
  125.     float    backoff;
  126.     float    change;
  127.     int        i;
  128.     
  129.     backoff = DotProduct (in, normal);
  130.     
  131.     if ( backoff < 0 ) {
  132.         backoff *= overbounce;
  133.     } else {
  134.         backoff /= overbounce;
  135.     }
  136.  
  137.     for ( i=0 ; i<3 ; i++ ) {
  138.         change = normal[i]*backoff;
  139.         out[i] = in[i] - change;
  140.     }
  141. }
  142.  
  143.  
  144. /*
  145. ==================
  146. PM_Friction
  147.  
  148. Handles both ground friction and water friction
  149. ==================
  150. */
  151. static void PM_Friction( void ) {
  152.     vec3_t    vec;
  153.     float    *vel;
  154.     float    speed, newspeed, control;
  155.     float    drop;
  156.     
  157.     vel = pm->ps->velocity;
  158.     
  159.     VectorCopy( vel, vec );
  160.     if ( pml.walking ) {
  161.         vec[2] = 0;    // ignore slope movement
  162.     }
  163.  
  164.     speed = VectorLength(vec);
  165.     if (speed < 1) {
  166.         vel[0] = 0;
  167.         vel[1] = 0;        // allow sinking underwater
  168.         // FIXME: still have z friction underwater?
  169.         return;
  170.     }
  171.  
  172.     drop = 0;
  173.  
  174.     // apply ground friction
  175.     if ( pm->waterlevel <= 1 ) {
  176.         if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) ) {
  177.             // if getting knocked back, no friction
  178.             if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) {
  179.                 control = speed < pm_stopspeed ? pm_stopspeed : speed;
  180.                 drop += control*pm_friction*pml.frametime;
  181.             }
  182.         }
  183.     }
  184.  
  185.     // apply water friction even if just wading
  186.     if ( pm->waterlevel ) {
  187.         drop += speed*pm_waterfriction*pm->waterlevel*pml.frametime;
  188.     }
  189.  
  190.     // apply flying friction
  191.     if ( pm->ps->powerups[PW_FLIGHT] || pm->ps->pm_type == PM_SPECTATOR ) {
  192.         drop += speed*pm_flightfriction*pml.frametime;
  193.     }
  194.  
  195.     // scale the velocity
  196.     newspeed = speed - drop;
  197.     if (newspeed < 0) {
  198.         newspeed = 0;
  199.     }
  200.     newspeed /= speed;
  201.  
  202.     vel[0] = vel[0] * newspeed;
  203.     vel[1] = vel[1] * newspeed;
  204.     vel[2] = vel[2] * newspeed;
  205. }
  206.  
  207.  
  208. /*
  209. ==============
  210. PM_Accelerate
  211.  
  212. Handles user intended acceleration
  213. ==============
  214. */
  215. static void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel ) {
  216. #if 1
  217.     // q2 style
  218.     int            i;
  219.     float        addspeed, accelspeed, currentspeed;
  220.  
  221.     currentspeed = DotProduct (pm->ps->velocity, wishdir);
  222.     addspeed = wishspeed - currentspeed;
  223.     if (addspeed <= 0) {
  224.         return;
  225.     }
  226.     accelspeed = accel*pml.frametime*wishspeed;
  227.     if (accelspeed > addspeed) {
  228.         accelspeed = addspeed;
  229.     }
  230.     
  231.     for (i=0 ; i<3 ; i++) {
  232.         pm->ps->velocity[i] += accelspeed*wishdir[i];    
  233.     }
  234. #else
  235.     // proper way (avoids strafe jump maxspeed bug), but feels bad
  236.     vec3_t        wishVelocity;
  237.     vec3_t        pushDir;
  238.     float        pushLen;
  239.     float        canPush;
  240.  
  241.     VectorScale( wishdir, wishspeed, wishVelocity );
  242.     VectorSubtract( wishVelocity, pm->ps->velocity, pushDir );
  243.     pushLen = VectorNormalize( pushDir );
  244.  
  245.     canPush = accel*pml.frametime*wishspeed;
  246.     if (canPush > pushLen) {
  247.         canPush = pushLen;
  248.     }
  249.  
  250.     VectorMA( pm->ps->velocity, canPush, pushDir, pm->ps->velocity );
  251. #endif
  252. }
  253.  
  254.  
  255.  
  256. /*
  257. ============
  258. PM_CmdScale
  259.  
  260. Returns the scale factor to apply to cmd movements
  261. This allows the clients to use axial -127 to 127 values for all directions
  262. without getting a sqrt(2) distortion in speed.
  263. ============
  264. */
  265. static float PM_CmdScale( usercmd_t *cmd ) {
  266.     int        max;
  267.     float    total;
  268.     float    scale;
  269.  
  270.     max = abs( cmd->forwardmove );
  271.     if ( abs( cmd->rightmove ) > max ) {
  272.         max = abs( cmd->rightmove );
  273.     }
  274.     if ( abs( cmd->upmove ) > max ) {
  275.         max = abs( cmd->upmove );
  276.     }
  277.     if ( !max ) {
  278.         return 0;
  279.     }
  280.  
  281.     total = sqrt( cmd->forwardmove * cmd->forwardmove
  282.         + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove );
  283.     scale = (float)pm->ps->speed * max / ( 127.0 * total );
  284.  
  285.     return scale;
  286. }
  287.  
  288.  
  289. /*
  290. ================
  291. PM_SetMovementDir
  292.  
  293. Determine the rotation of the legs reletive
  294. to the facing dir
  295. ================
  296. */
  297. static void PM_SetMovementDir( void ) {
  298.     if ( pm->cmd.forwardmove || pm->cmd.rightmove ) {
  299.         if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove > 0 ) {
  300.             pm->ps->movementDir = 0;
  301.         } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove > 0 ) {
  302.             pm->ps->movementDir = 1;
  303.         } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove == 0 ) {
  304.             pm->ps->movementDir = 2;
  305.         } else if ( pm->cmd.rightmove < 0 && pm->cmd.forwardmove < 0 ) {
  306.             pm->ps->movementDir = 3;
  307.         } else if ( pm->cmd.rightmove == 0 && pm->cmd.forwardmove < 0 ) {
  308.             pm->ps->movementDir = 4;
  309.         } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove < 0 ) {
  310.             pm->ps->movementDir = 5;
  311.         } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove == 0 ) {
  312.             pm->ps->movementDir = 6;
  313.         } else if ( pm->cmd.rightmove > 0 && pm->cmd.forwardmove > 0 ) {
  314.             pm->ps->movementDir = 7;
  315.         }
  316.     } else {
  317.         // if they aren't actively going directly sideways,
  318.         // change the animation to the diagonal so they
  319.         // don't stop too crooked
  320.         if ( pm->ps->movementDir == 2 ) {
  321.             pm->ps->movementDir = 1;
  322.         } else if ( pm->ps->movementDir == 6 ) {
  323.             pm->ps->movementDir = 7;
  324.         } 
  325.     }
  326. }
  327.  
  328.  
  329. /*
  330. =============
  331. PM_CheckJump
  332. =============
  333. */
  334. static qboolean PM_CheckJump( void ) {
  335.     if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
  336.         return qfalse;        // don't allow jump until all buttons are up
  337.     }
  338.  
  339.     if ( pm->cmd.upmove < 10 ) {
  340.         // not holding jump
  341.         return qfalse;
  342.     }
  343.  
  344.     // must wait for jump to be released
  345.     if ( pm->ps->pm_flags & PMF_JUMP_HELD ) {
  346.         // clear upmove so cmdscale doesn't lower running speed
  347.         pm->cmd.upmove = 0;
  348.         return qfalse;
  349.     }
  350.  
  351.     pml.groundPlane = qfalse;        // jumping away
  352.     pml.walking = qfalse;
  353.     pm->ps->pm_flags |= PMF_JUMP_HELD;
  354.  
  355.     pm->ps->groundEntityNum = ENTITYNUM_NONE;
  356.     pm->ps->velocity[2] = JUMP_VELOCITY;
  357.     PM_AddEvent( EV_JUMP );
  358.  
  359.     if ( pm->cmd.forwardmove >= 0 ) {
  360.         PM_ForceLegsAnim( LEGS_JUMP );
  361.         pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
  362.     } else {
  363.         PM_ForceLegsAnim( LEGS_JUMPB );
  364.         pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
  365.     }
  366.  
  367.     return qtrue;
  368. }
  369.  
  370. /*
  371. =============
  372. PM_CheckWaterJump
  373. =============
  374. */
  375. static qboolean    PM_CheckWaterJump( void ) {
  376.     vec3_t    spot;
  377.     int        cont;
  378.     vec3_t    flatforward;
  379.  
  380.     if (pm->ps->pm_time) {
  381.         return qfalse;
  382.     }
  383.  
  384.     // check for water jump
  385.     if ( pm->waterlevel != 2 ) {
  386.         return qfalse;
  387.     }
  388.  
  389.     flatforward[0] = pml.forward[0];
  390.     flatforward[1] = pml.forward[1];
  391.     flatforward[2] = 0;
  392.     VectorNormalize (flatforward);
  393.  
  394.     VectorMA (pm->ps->origin, 30, flatforward, spot);
  395.     spot[2] += 4;
  396.     cont = pm->pointcontents (spot, pm->ps->clientNum );
  397.     if ( !(cont & CONTENTS_SOLID) ) {
  398.         return qfalse;
  399.     }
  400.  
  401.     spot[2] += 16;
  402.     cont = pm->pointcontents (spot, pm->ps->clientNum );
  403.     if ( cont ) {
  404.         return qfalse;
  405.     }
  406.  
  407.     // jump out of water
  408.     VectorScale (pml.forward, 200, pm->ps->velocity);
  409.     pm->ps->velocity[2] = 350;
  410.  
  411.     pm->ps->pm_flags |= PMF_TIME_WATERJUMP;
  412.     pm->ps->pm_time = 2000;
  413.  
  414.     return qtrue;
  415. }
  416.  
  417. //============================================================================
  418.  
  419.  
  420. /*
  421. ===================
  422. PM_WaterJumpMove
  423.  
  424. Flying out of the water
  425. ===================
  426. */
  427. static void PM_WaterJumpMove( void ) {
  428.     // waterjump has no control, but falls
  429.  
  430.     PM_StepSlideMove( qtrue );
  431.  
  432.     pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
  433.     if (pm->ps->velocity[2] < 0) {
  434.         // cancel as soon as we are falling down again
  435.         pm->ps->pm_flags &= ~PMF_ALL_TIMES;
  436.         pm->ps->pm_time = 0;
  437.     }
  438. }
  439.  
  440. /*
  441. ===================
  442. PM_WaterMove
  443.  
  444. ===================
  445. */
  446. static void PM_WaterMove( void ) {
  447.     int        i;
  448.     vec3_t    wishvel;
  449.     float    wishspeed;
  450.     vec3_t    wishdir;
  451.     float    scale;
  452.     float    vel;
  453.  
  454.     if ( PM_CheckWaterJump() ) {
  455.         PM_WaterJumpMove();
  456.         return;
  457.     }
  458. #if 0
  459.     // jump = head for surface
  460.     if ( pm->cmd.upmove >= 10 ) {
  461.         if (pm->ps->velocity[2] > -300) {
  462.             if ( pm->watertype == CONTENTS_WATER ) {
  463.                 pm->ps->velocity[2] = 100;
  464.             } else if (pm->watertype == CONTENTS_SLIME) {
  465.                 pm->ps->velocity[2] = 80;
  466.             } else {
  467.                 pm->ps->velocity[2] = 50;
  468.             }
  469.         }
  470.     }
  471. #endif
  472.     PM_Friction ();
  473.  
  474.     scale = PM_CmdScale( &pm->cmd );
  475.     //
  476.     // user intentions
  477.     //
  478.     if ( !scale ) {
  479.         wishvel[0] = 0;
  480.         wishvel[1] = 0;
  481.         wishvel[2] = -60;        // sink towards bottom
  482.     } else {
  483.         for (i=0 ; i<3 ; i++)
  484.             wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;
  485.  
  486.         wishvel[2] += scale * pm->cmd.upmove;
  487.     }
  488.  
  489.     VectorCopy (wishvel, wishdir);
  490.     wishspeed = VectorNormalize(wishdir);
  491.  
  492.     if ( wishspeed > pm->ps->speed * pm_swimScale ) {
  493.         wishspeed = pm->ps->speed * pm_swimScale;
  494.     }
  495.  
  496.     PM_Accelerate (wishdir, wishspeed, pm_wateraccelerate);
  497.  
  498.     // make sure we can go up slopes easily under water
  499.     if ( pml.groundPlane && DotProduct( pm->ps->velocity, pml.groundTrace.plane.normal ) < 0 ) {
  500.         vel = VectorLength(pm->ps->velocity);
  501.         // slide along the ground plane
  502.         PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
  503.             pm->ps->velocity, OVERCLIP );
  504.  
  505.         VectorNormalize(pm->ps->velocity);
  506.         VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
  507.     }
  508.  
  509.     PM_SlideMove( qfalse );
  510. }
  511.  
  512.  
  513.  
  514. /*
  515. ===================
  516. PM_FlyMove
  517.  
  518. Only with the flight powerup
  519. ===================
  520. */
  521. static void PM_FlyMove( void ) {
  522.     int        i;
  523.     vec3_t    wishvel;
  524.     float    wishspeed;
  525.     vec3_t    wishdir;
  526.     float    scale;
  527.  
  528.     // normal slowdown
  529.     PM_Friction ();
  530.  
  531.     scale = PM_CmdScale( &pm->cmd );
  532.     //
  533.     // user intentions
  534.     //
  535.     if ( !scale ) {
  536.         wishvel[0] = 0;
  537.         wishvel[1] = 0;
  538.         wishvel[2] = 0;
  539.     } else {
  540.         for (i=0 ; i<3 ; i++) {
  541.             wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove + scale * pml.right[i]*pm->cmd.rightmove;
  542.         }
  543.  
  544.         wishvel[2] += scale * pm->cmd.upmove;
  545.     }
  546.  
  547.     VectorCopy (wishvel, wishdir);
  548.     wishspeed = VectorNormalize(wishdir);
  549.  
  550.     PM_Accelerate (wishdir, wishspeed, pm_flyaccelerate);
  551.  
  552.     PM_StepSlideMove( qfalse );
  553. }
  554.  
  555.  
  556. /*
  557. ===================
  558. PM_AirMove
  559.  
  560. ===================
  561. */
  562. static void PM_AirMove( void ) {
  563.     int            i;
  564.     vec3_t        wishvel;
  565.     float        fmove, smove;
  566.     vec3_t        wishdir;
  567.     float        wishspeed;
  568.     float        scale;
  569.     usercmd_t    cmd;
  570.  
  571.     PM_Friction();
  572.  
  573.     fmove = pm->cmd.forwardmove;
  574.     smove = pm->cmd.rightmove;
  575.  
  576.     cmd = pm->cmd;
  577.     scale = PM_CmdScale( &cmd );
  578.  
  579.     // set the movementDir so clients can rotate the legs for strafing
  580.     PM_SetMovementDir();
  581.  
  582.     // project moves down to flat plane
  583.     pml.forward[2] = 0;
  584.     pml.right[2] = 0;
  585.     VectorNormalize (pml.forward);
  586.     VectorNormalize (pml.right);
  587.  
  588.     for ( i = 0 ; i < 2 ; i++ ) {
  589.         wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
  590.     }
  591.     wishvel[2] = 0;
  592.  
  593.     VectorCopy (wishvel, wishdir);
  594.     wishspeed = VectorNormalize(wishdir);
  595.     wishspeed *= scale;
  596.  
  597.     // not on ground, so little effect on velocity
  598.     PM_Accelerate (wishdir, wishspeed, pm_airaccelerate);
  599.  
  600.     // we may have a ground plane that is very steep, even
  601.     // though we don't have a groundentity
  602.     // slide along the steep plane
  603.     if ( pml.groundPlane ) {
  604.         PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
  605.             pm->ps->velocity, OVERCLIP );
  606.     }
  607.  
  608. #if 0
  609.     //ZOID:  If we are on the grapple, try stair-stepping
  610.     //this allows a player to use the grapple to pull himself
  611.     //over a ledge
  612.     if (pm->ps->pm_flags & PMF_GRAPPLE_PULL)
  613.         PM_StepSlideMove ( qtrue );
  614.     else
  615.         PM_SlideMove ( qtrue );
  616. #endif
  617.  
  618.     PM_StepSlideMove ( qtrue );
  619. }
  620.  
  621. /*
  622. ===================
  623. PM_GrappleMove
  624.  
  625. ===================
  626. */
  627. static void PM_GrappleMove( void ) {
  628.     vec3_t vel, v;
  629.     float vlen;
  630.  
  631.     VectorScale(pml.forward, -16, v);
  632.     VectorAdd(pm->ps->grapplePoint, v, v);
  633.     VectorSubtract(v, pm->ps->origin, vel);
  634.     vlen = VectorLength(vel);
  635.     VectorNormalize( vel );
  636.  
  637.     if (vlen <= 100)
  638.         VectorScale(vel, 10 * vlen, vel);
  639.     else
  640.         VectorScale(vel, 800, vel);
  641.  
  642.     VectorCopy(vel, pm->ps->velocity);
  643.  
  644.     pml.groundPlane = qfalse;
  645. }
  646.  
  647. /*
  648. ===================
  649. PM_WalkMove
  650.  
  651. ===================
  652. */
  653. static void PM_WalkMove( void ) {
  654.     int            i;
  655.     vec3_t        wishvel;
  656.     float        fmove, smove;
  657.     vec3_t        wishdir;
  658.     float        wishspeed;
  659.     float        scale;
  660.     usercmd_t    cmd;
  661.     float        accelerate;
  662.     float        vel;
  663.  
  664.     if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) {
  665.         // begin swimming
  666.         PM_WaterMove();
  667.         return;
  668.     }
  669.  
  670.  
  671.     if ( PM_CheckJump () ) {
  672.         // jumped away
  673.         if ( pm->waterlevel > 1 ) {
  674.             PM_WaterMove();
  675.         } else {
  676.             PM_AirMove();
  677.         }
  678.         return;
  679.     }
  680.  
  681.     PM_Friction ();
  682.  
  683.     fmove = pm->cmd.forwardmove;
  684.     smove = pm->cmd.rightmove;
  685.  
  686.     cmd = pm->cmd;
  687.     scale = PM_CmdScale( &cmd );
  688.  
  689.     // set the movementDir so clients can rotate the legs for strafing
  690.     PM_SetMovementDir();
  691.  
  692.     // project moves down to flat plane
  693.     pml.forward[2] = 0;
  694.     pml.right[2] = 0;
  695.  
  696.     // project the forward and right directions onto the ground plane
  697.     PM_ClipVelocity (pml.forward, pml.groundTrace.plane.normal, pml.forward, OVERCLIP );
  698.     PM_ClipVelocity (pml.right, pml.groundTrace.plane.normal, pml.right, OVERCLIP );
  699.     //
  700.     VectorNormalize (pml.forward);
  701.     VectorNormalize (pml.right);
  702.  
  703.     for ( i = 0 ; i < 3 ; i++ ) {
  704.         wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
  705.     }
  706.     // when going up or down slopes the wish velocity should Not be zero
  707. //    wishvel[2] = 0;
  708.  
  709.     VectorCopy (wishvel, wishdir);
  710.     wishspeed = VectorNormalize(wishdir);
  711.     wishspeed *= scale;
  712.  
  713.     // clamp the speed lower if ducking
  714.     if ( pm->ps->pm_flags & PMF_DUCKED ) {
  715.         if ( wishspeed > pm->ps->speed * pm_duckScale ) {
  716.             wishspeed = pm->ps->speed * pm_duckScale;
  717.         }
  718.     }
  719.  
  720.     // clamp the speed lower if wading or walking on the bottom
  721.     if ( pm->waterlevel ) {
  722.         float    waterScale;
  723.  
  724.         waterScale = pm->waterlevel / 3.0;
  725.         waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale;
  726.         if ( wishspeed > pm->ps->speed * waterScale ) {
  727.             wishspeed = pm->ps->speed * waterScale;
  728.         }
  729.     }
  730.  
  731.     // when a player gets hit, they temporarily lose
  732.     // full control, which allows them to be moved a bit
  733.     if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
  734.         accelerate = pm_airaccelerate;
  735.     } else {
  736.         accelerate = pm_accelerate;
  737.     }
  738.  
  739.     PM_Accelerate (wishdir, wishspeed, accelerate);
  740.  
  741.     //Com_Printf("velocity = %1.1f %1.1f %1.1f\n", pm->ps->velocity[0], pm->ps->velocity[1], pm->ps->velocity[2]);
  742.     //Com_Printf("velocity1 = %1.1f\n", VectorLength(pm->ps->velocity));
  743.  
  744.     if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
  745.         pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
  746.     } else {
  747.         // don't reset the z velocity for slopes
  748. //        pm->ps->velocity[2] = 0;
  749.     }
  750.  
  751.     vel = VectorLength(pm->ps->velocity);
  752.  
  753.     // slide along the ground plane
  754.     PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, 
  755.         pm->ps->velocity, OVERCLIP );
  756.  
  757.     // don't decrease velocity when going up or down a slope
  758.     VectorNormalize(pm->ps->velocity);
  759.     VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
  760.  
  761.     // don't do anything if standing still
  762.     if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) {
  763.         return;
  764.     }
  765.  
  766.     PM_StepSlideMove( qfalse );
  767.  
  768.     //Com_Printf("velocity2 = %1.1f\n", VectorLength(pm->ps->velocity));
  769.  
  770. }
  771.  
  772.  
  773. /*
  774. ==============
  775. PM_DeadMove
  776. ==============
  777. */
  778. static void PM_DeadMove( void ) {
  779.     float    forward;
  780.  
  781.     if ( !pml.walking ) {
  782.         return;
  783.     }
  784.  
  785.     // extra friction
  786.  
  787.     forward = VectorLength (pm->ps->velocity);
  788.     forward -= 20;
  789.     if ( forward <= 0 ) {
  790.         VectorClear (pm->ps->velocity);
  791.     } else {
  792.         VectorNormalize (pm->ps->velocity);
  793.         VectorScale (pm->ps->velocity, forward, pm->ps->velocity);
  794.     }
  795. }
  796.  
  797.  
  798. /*
  799. ===============
  800. PM_NoclipMove
  801. ===============
  802. */
  803. static void PM_NoclipMove( void ) {
  804.     float    speed, drop, friction, control, newspeed;
  805.     int            i;
  806.     vec3_t        wishvel;
  807.     float        fmove, smove;
  808.     vec3_t        wishdir;
  809.     float        wishspeed;
  810.     float        scale;
  811.  
  812.     pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
  813.  
  814.     // friction
  815.  
  816.     speed = VectorLength (pm->ps->velocity);
  817.     if (speed < 1)
  818.     {
  819.         VectorCopy (vec3_origin, pm->ps->velocity);
  820.     }
  821.     else
  822.     {
  823.         drop = 0;
  824.  
  825.         friction = pm_friction*1.5;    // extra friction
  826.         control = speed < pm_stopspeed ? pm_stopspeed : speed;
  827.         drop += control*friction*pml.frametime;
  828.  
  829.         // scale the velocity
  830.         newspeed = speed - drop;
  831.         if (newspeed < 0)
  832.             newspeed = 0;
  833.         newspeed /= speed;
  834.  
  835.         VectorScale (pm->ps->velocity, newspeed, pm->ps->velocity);
  836.     }
  837.  
  838.     // accelerate
  839.     scale = PM_CmdScale( &pm->cmd );
  840.  
  841.     fmove = pm->cmd.forwardmove;
  842.     smove = pm->cmd.rightmove;
  843.     
  844.     for (i=0 ; i<3 ; i++)
  845.         wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
  846.     wishvel[2] += pm->cmd.upmove;
  847.  
  848.     VectorCopy (wishvel, wishdir);
  849.     wishspeed = VectorNormalize(wishdir);
  850.     wishspeed *= scale;
  851.  
  852.     PM_Accelerate( wishdir, wishspeed, pm_accelerate );
  853.  
  854.     // move
  855.     VectorMA (pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin);
  856. }
  857.  
  858. //============================================================================
  859.  
  860. /*
  861. ================
  862. PM_FootstepForSurface
  863.  
  864. Returns an event number apropriate for the groundsurface
  865. ================
  866. */
  867. static int PM_FootstepForSurface( void ) {
  868.     if ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) {
  869.         return 0;
  870.     }
  871.     if ( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) {
  872.         return EV_FOOTSTEP_METAL;
  873.     }
  874.     return EV_FOOTSTEP;
  875. }
  876.  
  877.  
  878. /*
  879. =================
  880. PM_CrashLand
  881.  
  882. Check for hard landings that generate sound events
  883. =================
  884. */
  885. static void PM_CrashLand( void ) {
  886.     float        delta;
  887.     float        dist;
  888.     float        vel, acc;
  889.     float        t;
  890.     float        a, b, c, den;
  891.  
  892.     // decide which landing animation to use
  893.     if ( pm->ps->pm_flags & PMF_BACKWARDS_JUMP ) {
  894.         PM_ForceLegsAnim( LEGS_LANDB );
  895.     } else {
  896.         PM_ForceLegsAnim( LEGS_LAND );
  897.     }
  898.  
  899.     pm->ps->legsTimer = TIMER_LAND;
  900.  
  901.     // calculate the exact velocity on landing
  902.     dist = pm->ps->origin[2] - pml.previous_origin[2];
  903.     vel = pml.previous_velocity[2];
  904.     acc = -pm->ps->gravity;
  905.  
  906.     a = acc / 2;
  907.     b = vel;
  908.     c = -dist;
  909.  
  910.     den =  b * b - 4 * a * c;
  911.     if ( den < 0 ) {
  912.         return;
  913.     }
  914.     t = (-b - sqrt( den ) ) / ( 2 * a );
  915.  
  916.     delta = vel + t * acc;
  917.     delta = delta*delta * 0.0001;
  918.  
  919.     // ducking while falling doubles damage
  920.     if ( pm->ps->pm_flags & PMF_DUCKED ) {
  921.         delta *= 2;
  922.     }
  923.  
  924.     // never take falling damage if completely underwater
  925.     if ( pm->waterlevel == 3 ) {
  926.         return;
  927.     }
  928.  
  929.     // reduce falling damage if there is standing water
  930.     if ( pm->waterlevel == 2 ) {
  931.         delta *= 0.25;
  932.     }
  933.     if ( pm->waterlevel == 1 ) {
  934.         delta *= 0.5;
  935.     }
  936.  
  937.     if ( delta < 1 ) {
  938.         return;
  939.     }
  940.  
  941.     // create a local entity event to play the sound
  942.  
  943.     // SURF_NODAMAGE is used for bounce pads where you don't ever
  944.     // want to take damage or play a crunch sound
  945.     if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) )  {
  946.         if ( delta > 60 ) {
  947.             PM_AddEvent( EV_FALL_FAR );
  948.         } else if ( delta > 40 ) {
  949.             // this is a pain grunt, so don't play it if dead
  950.             if ( pm->ps->stats[STAT_HEALTH] > 0 ) {
  951.                 PM_AddEvent( EV_FALL_MEDIUM );
  952.             }
  953.         } else if ( delta > 7 ) {
  954.             PM_AddEvent( EV_FALL_SHORT );
  955.         } else {
  956.             PM_AddEvent( PM_FootstepForSurface() );
  957.         }
  958.     }
  959.  
  960.     // start footstep cycle over
  961.     pm->ps->bobCycle = 0;
  962. }
  963.  
  964.  
  965.  
  966. /*
  967. =============
  968. PM_CorrectAllSolid
  969. =============
  970. */
  971. static void PM_CorrectAllSolid( void ) {
  972.     if ( pm->debugLevel ) {
  973.         Com_Printf("%i:allsolid\n", c_pmove);
  974.     }
  975.  
  976.     // FIXME: jitter around
  977.  
  978.     pm->ps->groundEntityNum = ENTITYNUM_NONE;
  979.     pml.groundPlane = qfalse;
  980.     pml.walking = qfalse;
  981. }
  982.  
  983.  
  984. /*
  985. =============
  986. PM_GroundTraceMissed
  987.  
  988. The ground trace didn't hit a surface, so we are in freefall
  989. =============
  990. */
  991. static void PM_GroundTraceMissed( void ) {
  992.     trace_t        trace;
  993.     vec3_t        point;
  994.  
  995.     if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) {
  996.         // we just transitioned into freefall
  997.         if ( pm->debugLevel ) {
  998.             Com_Printf("%i:lift\n", c_pmove);
  999.         }
  1000.  
  1001.         // if they aren't in a jumping animation and the ground is a ways away, force into it
  1002.         // if we didn't do the trace, the player would be backflipping down staircases
  1003.         VectorCopy( pm->ps->origin, point );
  1004.         point[2] -= 64;
  1005.  
  1006.         pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
  1007.         if ( trace.fraction == 1.0 ) {
  1008.             if ( pm->cmd.forwardmove >= 0 ) {
  1009.                 PM_ForceLegsAnim( LEGS_JUMP );
  1010.                 pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
  1011.             } else {
  1012.                 PM_ForceLegsAnim( LEGS_JUMPB );
  1013.                 pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
  1014.             }
  1015.         }
  1016.     }
  1017.  
  1018.     pm->ps->groundEntityNum = ENTITYNUM_NONE;
  1019.     pml.groundPlane = qfalse;
  1020.     pml.walking = qfalse;
  1021. }
  1022.  
  1023.  
  1024. /*
  1025. =============
  1026. PM_GroundTrace
  1027. =============
  1028. */
  1029. static void PM_GroundTrace( void ) {
  1030.     vec3_t        point;
  1031.     trace_t        trace;
  1032.  
  1033.     point[0] = pm->ps->origin[0];
  1034.     point[1] = pm->ps->origin[1];
  1035.     point[2] = pm->ps->origin[2] - 0.25;
  1036.  
  1037.     pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
  1038.     pml.groundTrace = trace;
  1039.  
  1040.     // do something corrective if the trace starts in a solid...
  1041.     if ( trace.allsolid ) {
  1042.         PM_CorrectAllSolid();
  1043.         return;
  1044.     }
  1045.  
  1046.     // if the trace didn't hit anything, we are in free fall
  1047.     if ( trace.fraction == 1.0 ) {
  1048.         PM_GroundTraceMissed();
  1049.         pml.groundPlane = qfalse;
  1050.         pml.walking = qfalse;
  1051.         return;
  1052.     }
  1053.  
  1054.     // check if getting thrown off the ground
  1055.     if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) {
  1056.         if ( pm->debugLevel ) {
  1057.             Com_Printf("%i:kickoff\n", c_pmove);
  1058.         }
  1059.         // go into jump animation
  1060.         if ( pm->cmd.forwardmove >= 0 ) {
  1061.             PM_ForceLegsAnim( LEGS_JUMP );
  1062.             pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
  1063.         } else {
  1064.             PM_ForceLegsAnim( LEGS_JUMPB );
  1065.             pm->ps->pm_flags |= PMF_BACKWARDS_JUMP;
  1066.         }
  1067.  
  1068.         pm->ps->groundEntityNum = ENTITYNUM_NONE;
  1069.         pml.groundPlane = qfalse;
  1070.         pml.walking = qfalse;
  1071.         return;
  1072.     }
  1073.     
  1074.     // slopes that are too steep will not be considered onground
  1075.     if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) {
  1076.         if ( pm->debugLevel ) {
  1077.             Com_Printf("%i:steep\n", c_pmove);
  1078.         }
  1079.         // FIXME: if they can't slide down the slope, let them
  1080.         // walk (sharp crevices)
  1081.         pm->ps->groundEntityNum = ENTITYNUM_NONE;
  1082.         pml.groundPlane = qtrue;
  1083.         pml.walking = qfalse;
  1084.         return;
  1085.     }
  1086.  
  1087.     pml.groundPlane = qtrue;
  1088.     pml.walking = qtrue;
  1089.  
  1090.     // hitting solid ground will end a waterjump
  1091.     if (pm->ps->pm_flags & PMF_TIME_WATERJUMP)
  1092.     {
  1093.         pm->ps->pm_flags &= ~(PMF_TIME_WATERJUMP | PMF_TIME_LAND);
  1094.         pm->ps->pm_time = 0;
  1095.     }
  1096.  
  1097.     if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
  1098.         // just hit the ground
  1099.         if ( pm->debugLevel ) {
  1100.             Com_Printf("%i:Land\n", c_pmove);
  1101.         }
  1102.         
  1103.         PM_CrashLand();
  1104.  
  1105.         // don't do landing time if we were just going down a slope
  1106.         if ( pml.previous_velocity[2] < -200 ) {
  1107.             // don't allow another jump for a little while
  1108.             pm->ps->pm_flags |= PMF_TIME_LAND;
  1109.             pm->ps->pm_time = 250;
  1110.         }
  1111.     }
  1112.  
  1113.     pm->ps->groundEntityNum = trace.entityNum;
  1114.  
  1115.     // don't reset the z velocity for slopes
  1116. //    pm->ps->velocity[2] = 0;
  1117.  
  1118.     PM_AddTouchEnt( trace.entityNum );
  1119. }
  1120.  
  1121.  
  1122. /*
  1123. =============
  1124. PM_SetWaterLevel    FIXME: avoid this twice?  certainly if not moving
  1125. =============
  1126. */
  1127. static void PM_SetWaterLevel( void ) {
  1128.     vec3_t        point;
  1129.     int            cont;
  1130.     int            sample1;
  1131.     int            sample2;
  1132.  
  1133.     //
  1134.     // get waterlevel, accounting for ducking
  1135.     //
  1136.     pm->waterlevel = 0;
  1137.     pm->watertype = 0;
  1138.  
  1139.     point[0] = pm->ps->origin[0];
  1140.     point[1] = pm->ps->origin[1];
  1141.     point[2] = pm->ps->origin[2] + MINS_Z + 1;    
  1142.     cont = pm->pointcontents( point, pm->ps->clientNum );
  1143.  
  1144.     if ( cont & MASK_WATER ) {
  1145.         sample2 = pm->ps->viewheight - MINS_Z;
  1146.         sample1 = sample2 / 2;
  1147.  
  1148.         pm->watertype = cont;
  1149.         pm->waterlevel = 1;
  1150.         point[2] = pm->ps->origin[2] + MINS_Z + sample1;
  1151.         cont = pm->pointcontents (point, pm->ps->clientNum );
  1152.         if ( cont & MASK_WATER ) {
  1153.             pm->waterlevel = 2;
  1154.             point[2] = pm->ps->origin[2] + MINS_Z + sample2;
  1155.             cont = pm->pointcontents (point, pm->ps->clientNum );
  1156.             if ( cont & MASK_WATER ){
  1157.                 pm->waterlevel = 3;
  1158.             }
  1159.         }
  1160.     }
  1161.  
  1162. }
  1163.  
  1164.  
  1165.  
  1166. /*
  1167. ==============
  1168. PM_CheckDuck
  1169.  
  1170. Sets mins, maxs, and pm->ps->viewheight
  1171. ==============
  1172. */
  1173. static void PM_CheckDuck (void)
  1174. {
  1175.     trace_t    trace;
  1176.  
  1177.     pm->mins[0] = -15;
  1178.     pm->mins[1] = -15;
  1179.  
  1180.     pm->maxs[0] = 15;
  1181.     pm->maxs[1] = 15;
  1182.  
  1183.     pm->mins[2] = MINS_Z;
  1184.  
  1185.     if (pm->ps->pm_type == PM_DEAD)
  1186.     {
  1187.         pm->maxs[2] = -8;
  1188.         pm->ps->viewheight = DEAD_VIEWHEIGHT;
  1189.         return;
  1190.     }
  1191.  
  1192.     if (pm->cmd.upmove < 0)
  1193.     {    // duck
  1194.         pm->ps->pm_flags |= PMF_DUCKED;
  1195.     }
  1196.     else
  1197.     {    // stand up if possible
  1198.         if (pm->ps->pm_flags & PMF_DUCKED)
  1199.         {
  1200.             // try to stand up
  1201.             pm->maxs[2] = 32;
  1202.             pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, pm->ps->origin, pm->ps->clientNum, pm->tracemask );
  1203.             if (!trace.allsolid)
  1204.                 pm->ps->pm_flags &= ~PMF_DUCKED;
  1205.         }
  1206.     }
  1207.  
  1208.     if (pm->ps->pm_flags & PMF_DUCKED)
  1209.     {
  1210.         pm->maxs[2] = 16;
  1211.         pm->ps->viewheight = CROUCH_VIEWHEIGHT;
  1212.     }
  1213.     else
  1214.     {
  1215.         pm->maxs[2] = 32;
  1216.         pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
  1217.     }
  1218. }
  1219.  
  1220.  
  1221.  
  1222. //===================================================================
  1223.  
  1224.  
  1225. /*
  1226. ===============
  1227. PM_Footsteps
  1228. ===============
  1229. */
  1230. static void PM_Footsteps( void ) {
  1231.     float        bobmove;
  1232.     int            old;
  1233.     qboolean    footstep;
  1234.  
  1235.     //
  1236.     // calculate speed and cycle to be used for
  1237.     // all cyclic walking effects
  1238.     //
  1239.     pm->xyspeed = sqrt( pm->ps->velocity[0] * pm->ps->velocity[0]
  1240.         +  pm->ps->velocity[1] * pm->ps->velocity[1] );
  1241.  
  1242.     if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {
  1243.         // airborne leaves position in cycle intact, but doesn't advance
  1244.         if ( pm->waterlevel > 1 ) {
  1245.             PM_ContinueLegsAnim( LEGS_SWIM );
  1246.         }
  1247.         return;
  1248.     }
  1249.  
  1250.     // if not trying to move
  1251.     if ( !pm->cmd.forwardmove && !pm->cmd.rightmove ) {
  1252.         if (  pm->xyspeed < 5 ) {
  1253.             pm->ps->bobCycle = 0;    // start at beginning of cycle again
  1254.             if ( pm->ps->pm_flags & PMF_DUCKED ) {
  1255.                 PM_ContinueLegsAnim( LEGS_IDLECR );
  1256.             } else {
  1257.                 PM_ContinueLegsAnim( LEGS_IDLE );
  1258.             }
  1259.         }
  1260.         return;
  1261.     }
  1262.     
  1263.  
  1264.     footstep = qfalse;
  1265.  
  1266.     if ( pm->ps->pm_flags & PMF_DUCKED ) {
  1267.         bobmove = 0.5;    // ducked characters bob much faster
  1268.         PM_ContinueLegsAnim( LEGS_WALKCR );
  1269.         // ducked characters never play footsteps
  1270.     } else     if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
  1271.         if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
  1272.             bobmove = 0.4;    // faster speeds bob faster
  1273.             footstep = qtrue;
  1274.         } else {
  1275.             bobmove = 0.3;
  1276.         }
  1277.         PM_ContinueLegsAnim( LEGS_BACK );
  1278.     } else {
  1279.         if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
  1280.             bobmove = 0.4;    // faster speeds bob faster
  1281.             PM_ContinueLegsAnim( LEGS_RUN );
  1282.             footstep = qtrue;
  1283.         } else {
  1284.             bobmove = 0.3;    // walking bobs slow
  1285.             PM_ContinueLegsAnim( LEGS_WALK );
  1286.         }
  1287.     }
  1288.  
  1289.     // check for footstep / splash sounds
  1290.     old = pm->ps->bobCycle;
  1291.     pm->ps->bobCycle = (int)( old + bobmove * pml.msec ) & 255;
  1292.  
  1293.     // if we just crossed a cycle boundary, play an apropriate footstep event
  1294.     if ( ( ( old + 64 ) ^ ( pm->ps->bobCycle + 64 ) ) & 128 ) {
  1295.         if ( pm->waterlevel == 0 ) {
  1296.             // on ground will only play sounds if running
  1297.             if ( footstep && !pm->noFootsteps ) {
  1298.                 PM_AddEvent( PM_FootstepForSurface() );
  1299.             }
  1300.         } else if ( pm->waterlevel == 1 ) {
  1301.             // splashing
  1302.             PM_AddEvent( EV_FOOTSPLASH );
  1303.         } else if ( pm->waterlevel == 2 ) {
  1304.             // wading / swimming at surface
  1305.             PM_AddEvent( EV_SWIM );
  1306.         } else if ( pm->waterlevel == 3 ) {
  1307.             // no sound when completely underwater
  1308.  
  1309.         }
  1310.     }
  1311. }
  1312.  
  1313. /*
  1314. ==============
  1315. PM_WaterEvents
  1316.  
  1317. Generate sound events for entering and leaving water
  1318. ==============
  1319. */
  1320. static void PM_WaterEvents( void ) {        // FIXME?
  1321.     //
  1322.     // if just entered a water volume, play a sound
  1323.     //
  1324.     if (!pml.previous_waterlevel && pm->waterlevel) {
  1325.         PM_AddEvent( EV_WATER_TOUCH );
  1326.     }
  1327.  
  1328.     //
  1329.     // if just completely exited a water volume, play a sound
  1330.     //
  1331.     if (pml.previous_waterlevel && !pm->waterlevel) {
  1332.         PM_AddEvent( EV_WATER_LEAVE );
  1333.     }
  1334.  
  1335.     //
  1336.     // check for head just going under water
  1337.     //
  1338.     if (pml.previous_waterlevel != 3 && pm->waterlevel == 3) {
  1339.         PM_AddEvent( EV_WATER_UNDER );
  1340.     }
  1341.  
  1342.     //
  1343.     // check for head just coming out of water
  1344.     //
  1345.     if (pml.previous_waterlevel == 3 && pm->waterlevel != 3) {
  1346.         PM_AddEvent( EV_WATER_CLEAR );
  1347.     }
  1348. }
  1349.  
  1350.  
  1351. /*
  1352. ===============
  1353. PM_BeginWeaponChange
  1354. ===============
  1355. */
  1356. static void PM_BeginWeaponChange( int weapon ) {
  1357.     if ( weapon <= WP_NONE || weapon >= WP_NUM_WEAPONS ) {
  1358.         return;
  1359.     }
  1360.  
  1361.     if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
  1362.         return;
  1363.     }
  1364.     
  1365.     if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
  1366.         return;
  1367.     }
  1368.  
  1369.     PM_AddEvent( EV_CHANGE_WEAPON );
  1370.     pm->ps->weaponstate = WEAPON_DROPPING;
  1371.     pm->ps->weaponTime += 200;
  1372.     PM_StartTorsoAnim( TORSO_DROP );
  1373. }
  1374.  
  1375.  
  1376. /*
  1377. ===============
  1378. PM_FinishWeaponChange
  1379. ===============
  1380. */
  1381. static void PM_FinishWeaponChange( void ) {
  1382.     int        weapon;
  1383.  
  1384.     weapon = pm->cmd.weapon;
  1385.     if ( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) {
  1386.         weapon = WP_NONE;
  1387.     }
  1388.  
  1389.     if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
  1390.         weapon = WP_NONE;
  1391.     }
  1392.  
  1393.     pm->ps->weapon = weapon;
  1394.     pm->ps->weaponstate = WEAPON_RAISING;
  1395.     pm->ps->weaponTime += 250;
  1396.     PM_StartTorsoAnim( TORSO_RAISE );
  1397. }
  1398.  
  1399.  
  1400. /*
  1401. ==============
  1402. PM_TorsoAnimation
  1403.  
  1404. ==============
  1405. */
  1406. static void PM_TorsoAnimation( void ) {
  1407.     if ( pm->ps->weaponstate == WEAPON_READY ) {
  1408.         if ( pm->ps->weapon == WP_GAUNTLET ) {
  1409.             PM_ContinueTorsoAnim( TORSO_STAND2 );
  1410.         } else {
  1411.             PM_ContinueTorsoAnim( TORSO_STAND );
  1412.         }
  1413.         return;
  1414.     }
  1415. }
  1416.  
  1417.  
  1418. /*
  1419. ==============
  1420. PM_Weapon
  1421.  
  1422. Generates weapon events and modifes the weapon counter
  1423. ==============
  1424. */
  1425. static void PM_Weapon( void ) {
  1426.     int        addTime;
  1427.  
  1428.     // don't allow attack until all buttons are up
  1429.     if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
  1430.         return;
  1431.     }
  1432.  
  1433.     // ignore if spectator
  1434.     if ( pm->ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) {
  1435.         return;
  1436.     }
  1437.  
  1438.     // check for dead player
  1439.     if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
  1440.         pm->ps->weapon = WP_NONE;
  1441.         return;
  1442.     }
  1443.  
  1444.     // check for item using
  1445.     if ( pm->cmd.buttons & BUTTON_USE_HOLDABLE ) {
  1446.         if ( ! ( pm->ps->pm_flags & PMF_USE_ITEM_HELD ) ) {
  1447.             if ( bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_MEDKIT
  1448.                 && pm->ps->stats[STAT_HEALTH] >= pm->ps->stats[STAT_MAX_HEALTH] ) {
  1449.                 // don't use medkit if at max health
  1450.             } else {
  1451.                 pm->ps->pm_flags |= PMF_USE_ITEM_HELD;
  1452.                 PM_AddEvent( EV_USE_ITEM0 + bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag );
  1453.                 pm->ps->stats[STAT_HOLDABLE_ITEM] = 0;
  1454.             }
  1455.             return;
  1456.         }
  1457.     } else {
  1458.         pm->ps->pm_flags &= ~PMF_USE_ITEM_HELD;
  1459.     }
  1460.  
  1461.  
  1462.     // make weapon function
  1463.     if ( pm->ps->weaponTime > 0 ) {
  1464.         pm->ps->weaponTime -= pml.msec;
  1465.     }
  1466.  
  1467.     // check for weapon change
  1468.     // can't change if weapon is firing, but can change
  1469.     // again if lowering or raising
  1470.     if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) {
  1471.         if ( pm->ps->weapon != pm->cmd.weapon ) {
  1472.             PM_BeginWeaponChange( pm->cmd.weapon );
  1473.         }
  1474.     }
  1475.  
  1476.     if ( pm->ps->weaponTime > 0 ) {
  1477.         return;
  1478.     }
  1479.  
  1480.     // change weapon if time
  1481.     if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
  1482.         PM_FinishWeaponChange();
  1483.         return;
  1484.     }
  1485.  
  1486.     if ( pm->ps->weaponstate == WEAPON_RAISING ) {
  1487.         pm->ps->weaponstate = WEAPON_READY;
  1488.         if ( pm->ps->weapon == WP_GAUNTLET ) {
  1489.             PM_StartTorsoAnim( TORSO_STAND2 );
  1490.         } else {
  1491.             PM_StartTorsoAnim( TORSO_STAND );
  1492.         }
  1493.         return;
  1494.     }
  1495.  
  1496.     // check for fire
  1497.     if ( ! (pm->cmd.buttons & 1) ) {
  1498.         pm->ps->weaponTime = 0;
  1499.         pm->ps->weaponstate = WEAPON_READY;
  1500.         return;
  1501.     }
  1502.  
  1503.     // start the animation even if out of ammo
  1504.     if ( pm->ps->weapon == WP_GAUNTLET ) {
  1505.         // the guantlet only "fires" when it actually hits something
  1506.         if ( !pm->gauntletHit ) {
  1507.             pm->ps->weaponTime = 0;
  1508.             pm->ps->weaponstate = WEAPON_READY;
  1509.             return;
  1510.         }
  1511.         PM_StartTorsoAnim( TORSO_ATTACK2 );
  1512.     } else {
  1513.         PM_StartTorsoAnim( TORSO_ATTACK );
  1514.     }
  1515.  
  1516.     pm->ps->weaponstate = WEAPON_FIRING;
  1517.  
  1518.     // check for out of ammo
  1519.     if ( ! pm->ps->ammo[ pm->ps->weapon ] ) {
  1520.         PM_AddEvent( EV_NOAMMO );
  1521.         pm->ps->weaponTime += 500;
  1522.         return;
  1523.     }
  1524.  
  1525.     // take an ammo away if not infinite
  1526.     if ( pm->ps->ammo[ pm->ps->weapon ] != -1 ) {
  1527.         pm->ps->ammo[ pm->ps->weapon ]--;
  1528.     }
  1529.  
  1530.     // fire weapon
  1531.     PM_AddEvent( EV_FIRE_WEAPON );
  1532.  
  1533.     switch( pm->ps->weapon ) {
  1534.     default:
  1535.     case WP_GAUNTLET:
  1536.         addTime = 400;
  1537.         break;
  1538.     case WP_LIGHTNING:
  1539.         addTime = 50;
  1540.         break;
  1541.     case WP_SHOTGUN:
  1542.         addTime = 1000;
  1543.         break;
  1544.     case WP_MACHINEGUN:
  1545.         addTime = 100;
  1546.         break;
  1547.     case WP_GRENADE_LAUNCHER:
  1548.         addTime = 800;
  1549.         break;
  1550.     case WP_ROCKET_LAUNCHER:
  1551.         addTime = 800;
  1552.         break;
  1553.     case WP_PLASMAGUN:
  1554.         addTime = 100;
  1555.         break;
  1556.     case WP_RAILGUN:
  1557.         addTime = 1500;
  1558.         break;
  1559.     case WP_BFG:
  1560. //        addTime = 100;
  1561.         addTime = 200;
  1562.         break;
  1563.     case WP_GRAPPLING_HOOK:
  1564.         addTime = 400;
  1565.         break;
  1566.     }
  1567.  
  1568.     if ( pm->ps->powerups[PW_HASTE] ) {
  1569.         addTime /= 1.3;
  1570.     }
  1571.  
  1572.     pm->ps->weaponTime += addTime;
  1573. }
  1574.  
  1575. /*
  1576. ================
  1577. PM_Animate
  1578. ================
  1579. */
  1580. static void PM_Animate( void ) {
  1581.     if ( pm->cmd.buttons & BUTTON_GESTURE ) {
  1582.         if ( pm->ps->torsoTimer == 0 ) {
  1583.             PM_StartTorsoAnim( TORSO_GESTURE );
  1584.             pm->ps->torsoTimer = TIMER_GESTURE;
  1585.             PM_AddEvent( EV_TAUNT );
  1586.         }
  1587.     }
  1588. }
  1589.  
  1590.  
  1591. /*
  1592. ================
  1593. PM_DropTimers
  1594. ================
  1595. */
  1596. static void PM_DropTimers( void ) {
  1597.     // drop misc timing counter
  1598.     if ( pm->ps->pm_time ) {
  1599.         if ( pml.msec >= pm->ps->pm_time ) {
  1600.             pm->ps->pm_flags &= ~PMF_ALL_TIMES;
  1601.             pm->ps->pm_time = 0;
  1602.         } else {
  1603.             pm->ps->pm_time -= pml.msec;
  1604.         }
  1605.     }
  1606.  
  1607.     // drop animation counter
  1608.     if ( pm->ps->legsTimer > 0 ) {
  1609.         pm->ps->legsTimer -= pml.msec;
  1610.         if ( pm->ps->legsTimer < 0 ) {
  1611.             pm->ps->legsTimer = 0;
  1612.         }
  1613.     }
  1614.  
  1615.     if ( pm->ps->torsoTimer > 0 ) {
  1616.         pm->ps->torsoTimer -= pml.msec;
  1617.         if ( pm->ps->torsoTimer < 0 ) {
  1618.             pm->ps->torsoTimer = 0;
  1619.         }
  1620.     }
  1621. }
  1622.  
  1623. /*
  1624. ================
  1625. PM_UpdateViewAngles
  1626.  
  1627. This can be used as another entry point when only the viewangles
  1628. are being updated isntead of a full move
  1629. ================
  1630. */
  1631. void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) {
  1632.     short        temp;
  1633.     int        i;
  1634.  
  1635.     if ( ps->pm_type == PM_INTERMISSION ) {
  1636.         return;        // no view changes at all
  1637.     }
  1638.  
  1639.     if ( ps->pm_type != PM_SPECTATOR && ps->stats[STAT_HEALTH] <= 0 ) {
  1640.         return;        // no view changes at all
  1641.     }
  1642.  
  1643.     // circularly clamp the angles with deltas
  1644.     for (i=0 ; i<3 ; i++) {
  1645.         temp = cmd->angles[i] + ps->delta_angles[i];
  1646.         if ( i == PITCH ) {
  1647.             // don't let the player look up or down more than 90 degrees
  1648.             if ( temp > 16000 ) {
  1649.                 ps->delta_angles[i] = 16000 - cmd->angles[i];
  1650.                 temp = 16000;
  1651.             } else if ( temp < -16000 ) {
  1652.                 ps->delta_angles[i] = -16000 - cmd->angles[i];
  1653.                 temp = -16000;
  1654.             }
  1655.         }
  1656.         ps->viewangles[i] = SHORT2ANGLE(temp);
  1657.     }
  1658.  
  1659. }
  1660.  
  1661.  
  1662. /*
  1663. ================
  1664. PmoveSingle
  1665.  
  1666. ================
  1667. */
  1668. void PmoveSingle (pmove_t *pmove) {
  1669.     pm = pmove;
  1670.  
  1671.     // this counter lets us debug movement problems with a journal
  1672.     // by setting a conditional breakpoint fot the previous frame
  1673.     c_pmove++;
  1674.  
  1675.     // clear results
  1676.     pm->numtouch = 0;
  1677.     pm->watertype = 0;
  1678.     pm->waterlevel = 0;
  1679.  
  1680.     if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
  1681.         pm->tracemask &= ~CONTENTS_BODY;    // corpses can fly through bodies
  1682.     }
  1683.  
  1684.     // make sure walking button is clear if they are running, to avoid
  1685.     // proxy no-footsteps cheats
  1686.     if ( abs( pm->cmd.forwardmove ) > 64 || abs( pm->cmd.rightmove ) > 64 ) {
  1687.         pm->cmd.buttons &= ~BUTTON_WALKING;
  1688.     }
  1689.  
  1690.     // set the talk balloon flag
  1691.     if ( pm->cmd.buttons & BUTTON_TALK ) {
  1692.         pm->ps->eFlags |= EF_TALK;
  1693.     } else {
  1694.         pm->ps->eFlags &= ~EF_TALK;
  1695.     }
  1696.  
  1697.     // set the firing flag for continuous beam weapons
  1698.     if ( !(pm->ps->pm_flags & PMF_RESPAWNED) && pm->ps->pm_type != PM_INTERMISSION
  1699.         && ( pm->cmd.buttons & BUTTON_ATTACK ) && pm->ps->ammo[ pm->ps->weapon ] ) {
  1700.         pm->ps->eFlags |= EF_FIRING;
  1701.     } else {
  1702.         pm->ps->eFlags &= ~EF_FIRING;
  1703.     }
  1704.  
  1705.     // clear the respawned flag if attack and use are cleared
  1706.     if ( pm->ps->stats[STAT_HEALTH] > 0 && 
  1707.         !( pm->cmd.buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE) ) ) {
  1708.         pm->ps->pm_flags &= ~PMF_RESPAWNED;
  1709.     }
  1710.  
  1711.     // if talk button is down, dissallow all other input
  1712.     // this is to prevent any possible intercept proxy from
  1713.     // adding fake talk balloons
  1714.     if ( pmove->cmd.buttons & BUTTON_TALK ) {
  1715.         pmove->cmd.buttons = 0;
  1716.         pmove->cmd.forwardmove = 0;
  1717.         pmove->cmd.rightmove = 0;
  1718.         pmove->cmd.upmove = 0;
  1719.     }
  1720.  
  1721.     // clear all pmove local vars
  1722.     memset (&pml, 0, sizeof(pml));
  1723.  
  1724.     // determine the time
  1725.     pml.msec = pmove->cmd.serverTime - pm->ps->commandTime;
  1726.     if ( pml.msec < 1 ) {
  1727.         pml.msec = 1;
  1728.     } else if ( pml.msec > 200 ) {
  1729.         pml.msec = 200;
  1730.     }
  1731.     pm->ps->commandTime = pmove->cmd.serverTime;
  1732.  
  1733.     // save old org in case we get stuck
  1734.     VectorCopy (pm->ps->origin, pml.previous_origin);
  1735.  
  1736.     // save old velocity for crashlanding
  1737.     VectorCopy (pm->ps->velocity, pml.previous_velocity);
  1738.  
  1739.     pml.frametime = pml.msec * 0.001;
  1740.  
  1741.     // update the viewangles
  1742.     PM_UpdateViewAngles( pm->ps, &pm->cmd );
  1743.  
  1744.     AngleVectors (pm->ps->viewangles, pml.forward, pml.right, pml.up);
  1745.  
  1746.     if ( pm->cmd.upmove < 10 ) {
  1747.         // not holding jump
  1748.         pm->ps->pm_flags &= ~PMF_JUMP_HELD;
  1749.     }
  1750.  
  1751.     // decide if backpedaling animations should be used
  1752.     if ( pm->cmd.forwardmove < 0 ) {
  1753.         pm->ps->pm_flags |= PMF_BACKWARDS_RUN;
  1754.     } else if ( pm->cmd.forwardmove > 0 || ( pm->cmd.forwardmove == 0 && pm->cmd.rightmove ) ) {
  1755.         pm->ps->pm_flags &= ~PMF_BACKWARDS_RUN;
  1756.     }
  1757.  
  1758.     if ( pm->ps->pm_type >= PM_DEAD ) {
  1759.         pm->cmd.forwardmove = 0;
  1760.         pm->cmd.rightmove = 0;
  1761.         pm->cmd.upmove = 0;
  1762.     }
  1763.  
  1764.     if ( pm->ps->pm_type == PM_SPECTATOR ) {
  1765.         PM_CheckDuck ();
  1766.         PM_FlyMove ();
  1767.         PM_DropTimers ();
  1768.         return;
  1769.     }
  1770.  
  1771.     if ( pm->ps->pm_type == PM_NOCLIP ) {
  1772.         PM_NoclipMove ();
  1773.         PM_DropTimers ();
  1774.         return;
  1775.     }
  1776.  
  1777.     if (pm->ps->pm_type == PM_FREEZE) {
  1778.         return;        // no movement at all
  1779.     }
  1780.  
  1781.     if ( pm->ps->pm_type == PM_INTERMISSION ) {
  1782.         return;        // no movement at all
  1783.     }
  1784.  
  1785.     // set watertype, and waterlevel
  1786.     PM_SetWaterLevel();
  1787.     pml.previous_waterlevel = pmove->waterlevel;
  1788.  
  1789.     // set mins, maxs, and viewheight
  1790.     PM_CheckDuck ();
  1791.  
  1792.     // set groundentity
  1793.     PM_GroundTrace();
  1794.  
  1795.     if ( pm->ps->pm_type == PM_DEAD ) {
  1796.         PM_DeadMove ();
  1797.     }
  1798.  
  1799.     PM_DropTimers();
  1800.  
  1801.     if ( pm->ps->powerups[PW_FLIGHT] ) {
  1802.         // flight powerup doesn't allow jump and has different friction
  1803.         PM_FlyMove();
  1804.     } else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) {
  1805.         PM_GrappleMove();
  1806.         // We can wiggle a bit
  1807.         PM_AirMove();
  1808.     } else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) {
  1809.         PM_WaterJumpMove();
  1810.     } else if ( pm->waterlevel > 1 ) {
  1811.         // swimming
  1812.         PM_WaterMove();
  1813.     } else if ( pml.walking ) {
  1814.         // walking on ground
  1815.         PM_WalkMove();
  1816.     } else {
  1817.         // airborne
  1818.         PM_AirMove();
  1819.     }
  1820.  
  1821.     PM_Animate();
  1822.  
  1823.     // set groundentity, watertype, and waterlevel
  1824.     PM_GroundTrace();
  1825.     PM_SetWaterLevel();
  1826.  
  1827.     // weapons
  1828.     PM_Weapon();
  1829.  
  1830.     // torso animation
  1831.     PM_TorsoAnimation();
  1832.  
  1833.     // footstep events / legs animations
  1834.     PM_Footsteps();
  1835.  
  1836.     // entering / leaving water splashes
  1837.     PM_WaterEvents();
  1838.  
  1839.     // snap some parts of playerstate to save network bandwidth
  1840.     SnapVector( pm->ps->velocity );
  1841. }
  1842.  
  1843.  
  1844. /*
  1845. ================
  1846. Pmove
  1847.  
  1848. Can be called by either the server or the client
  1849. ================
  1850. */
  1851. void Pmove (pmove_t *pmove) {
  1852.     int            finalTime;
  1853.  
  1854.     finalTime = pmove->cmd.serverTime;
  1855.  
  1856.     if ( finalTime < pmove->ps->commandTime ) {
  1857.         return;    // should not happen
  1858.     }
  1859.  
  1860.     if ( finalTime > pmove->ps->commandTime + 1000 ) {
  1861.         pmove->ps->commandTime = finalTime - 1000;
  1862.     }
  1863.  
  1864.     // chop the move up if it is too long, to prevent framerate
  1865.     // dependent behavior
  1866.     while ( pmove->ps->commandTime != finalTime ) {
  1867.         int        msec;
  1868.  
  1869.         msec = finalTime - pmove->ps->commandTime;
  1870.  
  1871.         if ( msec > 66 ) {
  1872.             msec = 66;
  1873.         }
  1874.         pmove->cmd.serverTime = pmove->ps->commandTime + msec;
  1875.         PmoveSingle( pmove );
  1876.     }
  1877.  
  1878. }
  1879.